package Methodes;

import java.util.Arrays;

import DataIO.Data;
import DataIO.ReelleHydraulique;
import DataIO.ReelleThermique;
import ilog.concert.*;
import ilog.cplex.*;
/**
 * Classe pour la résolution exacte du problème avec recours.
 * @author poko
 *
 */
public class Rec_Cplex extends Methode{
	
	/** Model cplex */
	IloCplex model;
	
	/** Var x de cout */
	IloNumVar[][] tabx;
	
	/** Vars pour le recours 0-> q+ 1-> q- */
	IloNumVar[][][] tabrecours;
	
	/** Data thermique reelle */
	ReelleThermique rt;
	
	/** Data hydraulique reelle */
	ReelleHydraulique rh;
	
	
	/**
	 * Construit une instance de Rec_Cplex 
	 * @param da les datas communes
	 * @param reth les datas reelles thermiques
	 * @param rehy les datas reelles hydraulique
	 * @throws IloException
	 */
	public Rec_Cplex(Data da, ReelleThermique reth, ReelleHydraulique rehy) throws IloException {
		model=new IloCplex();
		tabx= new IloNumVar[7][5];
		tabrecours= new IloNumVar[7][2][100];
		data = da;
		rt=reth;
		rh=rehy;
	}
	
	/**
	 * Initialise le model et lance la résolution
	 * @throws IloException
	 */
	public void solve() throws IloException{
		//fonction obj
		IloNumExpr obj = model.linearNumExpr() ;
		for(int i=0;i<7;i++){
			int j = 0;
			for(double cout : data.getCout()){
				IloNumVar v =  model.numVar(0.0, Double.MAX_VALUE);
				obj= model.sum(obj,model.prod(v, cout));
				model.addGe(v, 0);
				tabx[i][j]=v;
				j++;
			}
		}
		for(int k=0;k<7;k++)
			for(int i=0;i<100;i++){
				for (int j=0;j<2;j++){
					IloNumVar v =  model.numVar(0.0, Double.MAX_VALUE);
					tabrecours[k][j][i]=v;
					//obj= model.sum(obj,model.prod(v, (j+1)*100));
					//obj= model.sum(obj,model.prod(v, 100));
					//On divise le truc devant q+ par le nombre de scenarios
					obj= model.sum(obj,model.prod(v, (j+1)));

					model.addGe(v, 0);
				}
			}
		model.addMinimize( obj);
		//Scenarios 4 7 100
		double scenarios[][][]=rt.getCentrales();
		//scenarios x + q+ - q- = demande
		double demande[][]=data.getDemande();
		for(int i = 0; i<7;i++){
			for(int  j = 0; j<100; j++){
				IloNumExpr constraint = model.linearNumExpr();
				for(int k = 0; k<5 ; k++){
					if (k<4)constraint = model.sum(constraint,model.prod(tabx[i][k],scenarios[k][i][j] ) );
					if (k==4) constraint = model.sum(constraint,model.prod(tabx[i][k],rh.getRho() ) );

				}
				constraint = model.sum(constraint,tabrecours[i][0][j]);
				constraint = model.diff(constraint,tabrecours[i][1][j]);
				model.addEq(constraint,demande[i][j] );
			}
		}
		//Bornes capacité
		double[][] capacites = data.getCapacitemax();
		for(int i = 0; i<7;i++){
			for(int k = 0; k<5 ; k++){
				model.addLe(tabx[i][k], capacites[k][i] );
			}
		}
		double[] vmax = rh.getVmax();
		for(int i = 0; i<7; i++){
			IloNumExpr constraint = model.linearNumExpr();
			for(int j=0; j<i+1;j++){
				constraint=model.sum(constraint,tabx[j][4]);
			}
			model.addLe(constraint,vmax[i]);
		}
		double tempExecution=-model.getCplexTime();
		model.solve();
		tempExecution+=model.getCplexTime();
		System.out.println(model.getStatus());
		System.out.println(model.getObjValue());
		model.exportModel("recours.lp");
		
		double[][] meilleureSolution = new double[5][7];
		for(int i=0; i<5; i++){
			for (int j=0; j<7; j++){
				meilleureSolution[i][j]=model.getValue(tabx[j][i]);
			}
		}
		double[] maxCentrale1 = data.getMaxParCentrale().get(0);
		double[] maxCentrale2 = data.getMaxParCentrale().get(1);
		double[] maxCentrale3 = data.getMaxParCentrale().get(2);
		double[] maxCentrale4 = data.getMaxParCentrale().get(3);
		double[] maxCentrale5 = data.getMaxParCentrale().get(4);
		double coutMinimum=model.getObjValue();
		System.out.println("Exec: "+tempExecution);
		System.out.println("Exec: "+Arrays.deepToString(meilleureSolution));
		solution = new Solution(meilleureSolution, maxCentrale1, maxCentrale2, maxCentrale3, maxCentrale4, maxCentrale5, coutMinimum, tempExecution);
		model.end();
	}

}
